from nicegui import ui
from functools import partial
from typing import Any, Callable, List, Optional


class MenuItem:
    def __init__(
        self,
        name: str,
        children: Optional[List["MenuItem"]] = None,
        *,
        key: Optional[str] = None,
        on_click: Optional[Callable[[str], Any]] = None,
    ):
        """菜单项

        Args:
            name (str): 菜单项名称
            children (Optional[List["MenuItem"]], optional): 子菜单项列表. Defaults to None.
            key (Optional[str], optional): 菜单项唯一标识.点击事件参数传递使用. 如果 `None`，则使用菜单项名称. Defaults to None.
            on_click (Optional[Callable[str, Any]], optional): 点击事件处理函数. Defaults to None.
        """
        self.name = name
        self.children = children if children is not None else []
        self.key = key or name

        self.on_click = on_click


def create_menu(
    menu_items: List[MenuItem],
    default_on_click: Optional[Callable[[str], Any]] = None,
):
    """快速创建子级菜单

    Args:
        menu_items (List[MenuItem]): 菜单项列表
        default_on_click (Optional[Callable[[str], Any]], optional): 默认点击事件处理函数，如果菜单项没有设置事件处理函数，则使用默认事件处理函数. Defaults to None.
    """

    def _create_menu_items(items: List[MenuItem]):
        for item in items:
            with ui.menu_item(auto_close=not bool(item.children)) as menu_item:
                on_click = item.on_click or default_on_click

                if (not item.children) and on_click:
                    menu_item.on_click(partial(on_click, item.key))

                ui.item_section(item.name)

                if item.children:
                    with ui.item_section().props("side"):
                        ui.icon("keyboard_arrow_right")

                    with ui.menu().props('anchor="top end" self="top start"'):
                        with ui.list().props("dense"):
                            _create_menu_items(item.children)

    with ui.menu():
        _create_menu_items(menu_items)


# 使用示例
def when_click_some_item(key: str):
    ui.notify(f"clicked {key}")


menu_structure = [
    MenuItem(
        name="File",
        children=[
            MenuItem(
                name="New", children=[MenuItem(name="Project"), MenuItem(name="File")]
            ),
            MenuItem(name="Open"),
            MenuItem(name="Save"),
        ],
    ),
    MenuItem(name="Edit", children=[MenuItem(name="Undo"), MenuItem(name="Redo")]),
    MenuItem(name="View"),
]

with ui.button("click"):
    create_menu(menu_structure, default_on_click=when_click_some_item)


ui.run()
